package com.wgchao.amc.service.impl;

import com.wgchao.amc.common.EvaluateInfo;
import com.wgchao.amc.common.EvaluateMethod;
import com.wgchao.amc.common.PageData;
import com.wgchao.amc.common.ResultCommon;
import com.wgchao.amc.entity.autho.*;
import com.wgchao.amc.entity.base.SysBaseFunc;
import com.wgchao.amc.entity.base.SysBaseMenu;
import com.wgchao.amc.entity.menu.SysMenuProject;
import com.wgchao.amc.mapstruct.dto.SysBaseFuncDTO;
import com.wgchao.amc.mapstruct.dto.SysBaseMenuDTO;
import com.wgchao.amc.mapstruct.dto.SysMenuProjectDTO;
import com.wgchao.amc.mapstruct.mapper.SysBaseFuncMapper;
import com.wgchao.amc.mapstruct.mapper.SysMenuProjectMapper;
import com.wgchao.amc.mapstruct.mapper.expand.SysBaseMenuMapperExpand;
import com.wgchao.amc.repository.autho.*;
import com.wgchao.amc.repository.base.SysBaseFuncRepository;
import com.wgchao.amc.repository.base.SysBaseMenuRepository;
import com.wgchao.amc.repository.menu.SysMenuProjectRepository;
import com.wgchao.amc.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @作者：wgchao
 * @时间：22:03 2019/10/29 0029
 * @用途：
 **/
@Service
@Transactional
public class MenuServiceImpl implements MenuService {
    @Autowired
    private SysBaseMenuRepository menuRepository;
    @Autowired
    private SysMenuProjectRepository projectRepository;
    @Autowired
    private SysBaseMenuMapperExpand menuMapperExpand;
    @Autowired
    private SysMenuProjectMapper projectMapper;
    @Autowired
    private SysBaseFuncRepository funcRepository;
    @Autowired
    private SysBaseFuncMapper funcMapper;
    @Autowired
    private SysAuthoGroupRepository authoGroupRepository;
    @Autowired
    private SysAuthoGroupFuncRepository authoGroupFuncRepository;
    @Autowired
    private SysAuthoRoleRepository authoRoleRepository;
    @Autowired
    private SysAuthoRoleFuncRepository authoRoleFuncRepository;
    @Autowired
    private SysAuthoUserRepository authoUserRepository;
    @Autowired
    private SysAuthoUserFuncRepository authoUserFuncRepository;


    /**
     * 新增菜单
     * @param menuDTO 菜单信息
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseMenuDTO> save(SysBaseMenuDTO menuDTO) throws Exception {
        EvaluateInfo evaluateInfo = evaluate(menuDTO, menuD -> {
            SysBaseMenuDTO menuDTO1 = (SysBaseMenuDTO) menuD;
            SysMenuProject project = projectRepository.findFirstByProMark(menuDTO1.getProMark());
            if(project == null){
                return new EvaluateInfo(false, "项目不存在");
            }
            return new EvaluateInfo(true, null);
        });
        if(!evaluateInfo.isSuccess()){
            return ResultCommon.fail(evaluateInfo.getMsg());
        }

        SysBaseMenu menu = menuMapperExpand.toEntity(menuDTO);
        menu.setCreateTime(new Date());
        menu = menuRepository.save(menu);

        menuDTO = menuMapperExpand.toDTO(menu);
        menuDTO = menuMapperExpand.getFuncs(menuDTO);
        return ResultCommon.success().setData(menuDTO);
    }

    /**
     * 分页查询菜单信息
     * @param proMark 项目标示
     * @param page
     * @param limit
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<PageData<SysBaseMenuDTO>> page(String proMark, int page, int limit) throws Exception {
        Specification<SysBaseMenu> specification = new Specification<SysBaseMenu>() {
            @Override
            public Predicate toPredicate(Root<SysBaseMenu> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.equal(root.get("proMark"), proMark);
                return predicate;
            }
        };
        Pageable pageable = PageRequest.of(page-1, limit);

        Page<SysBaseMenu> menuPage = menuRepository.findAll(specification, pageable);
        List<SysBaseMenuDTO> menuDTOS = menuPage.get().map(menu -> {
            SysBaseMenuDTO menuDTO = menuMapperExpand.toDTO(menu);
            menuDTO = menuMapperExpand.getFuncs(menuDTO);
            return menuDTO;
        }).collect(Collectors.toList());

        return ResultCommon.success().setData(new PageData<SysBaseMenuDTO>(page, limit,
                Long.valueOf(menuPage.getTotalElements()).intValue(), menuDTOS));
    }

    /**
     * 查询菜单详细信息
     * @param menuId 菜单ID
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(readOnly = true)
    public ResultCommon<SysBaseMenuDTO> search(Long menuId) throws Exception {
        Optional<SysBaseMenu> menuOptional = menuRepository.findById(menuId);
        if(!menuOptional.isPresent()){
            return ResultCommon.fail("菜单不存在");
        }
        SysBaseMenu menu = menuOptional.get();

        SysBaseMenuDTO menuDTO = menuMapperExpand.toDTO(menu);
        menuDTO = menuMapperExpand.getFuncs(menuDTO);
        return ResultCommon.success().setData(menuDTO);
    }

    /**
     * 更新菜单信息
     * @param menuDTO 菜单信息
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseMenuDTO> update(SysBaseMenuDTO menuDTO) throws Exception {
        EvaluateInfo evaluateInfo = evaluate(menuDTO, menuD -> {
            SysBaseMenuDTO mDTO = (SysBaseMenuDTO) menuD;
            Optional<SysBaseMenu> menuOptional = menuRepository.findById(mDTO.getId());
            if(!menuOptional.isPresent()){
                return new EvaluateInfo(false, "菜单信息不存在");
            }
            return new EvaluateInfo(true, null);
        });
        if(!evaluateInfo.isSuccess()){
            return ResultCommon.fail(evaluateInfo.getMsg());
        }

        SysBaseMenu menu = menuMapperExpand.toEntity(menuDTO);
        menu = menuRepository.save(menu);

        menuDTO = menuMapperExpand.toDTO(menu);
        menuDTO = menuMapperExpand.getFuncs(menuDTO);
        return ResultCommon.success().setData(menuDTO);
    }

    /**
     * 删除菜单信息
     * @param menuId 菜单ID
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseMenuDTO> delete(Long menuId) throws Exception {
        Optional<SysBaseMenu> menuOptional = menuRepository.findById(menuId);
        if(!menuOptional.isPresent()){
            return ResultCommon.fail("菜单不存在");
        }
        SysBaseMenu menu = menuOptional.get();
        menuRepository.delete(menu);

        return ResultCommon.success();
    }


    /**
     * 分页查询项目列表
     * @param page
     * @param limit
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<PageData<SysMenuProjectDTO>> page(int page, int limit) throws Exception {
        Pageable pageable = PageRequest.of(page-1, limit);
        Page<SysMenuProject> projects = projectRepository.findAll(pageable);
        return ResultCommon.success().setData(new PageData(page, limit,
                Long.valueOf(projects.getTotalElements()).intValue(), projectMapper.toDTO(projects.getContent())));
    }

    /**
     * 新增项目信息
     * @param projectDTO
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysMenuProjectDTO> save(SysMenuProjectDTO projectDTO) throws Exception {
        SysMenuProject project = projectRepository.findFirstByProMark(projectDTO.getProMark());
        if(project != null){
            return ResultCommon.fail("项目标示已存在");
        }
        project = projectMapper.toEntity(projectDTO);

        project = projectRepository.save(project);

        return ResultCommon.success().setData(projectMapper.toDTO(project));
    }

    /**
     * 删除项目信息
     * @param proid 项目ID
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysMenuProjectDTO> deletePro(Long proid) throws Exception {
        Optional<SysMenuProject> projectOptional = projectRepository.findById(proid);
        if(!projectOptional.isPresent()){
            return ResultCommon.fail("项目信息不存在");
        }
        SysMenuProject project = projectOptional.get();
        projectRepository.delete(project);

        // 删除菜单相关的信息
        List<SysBaseMenu> menuList = menuRepository.findAllByProMark(project.getProMark());
        if(menuList!=null && !menuList.isEmpty()){
            for(SysBaseMenu menu:menuList){
                List<SysBaseFunc> funcList = funcRepository.findAllByMenuId(menu.getId());
                if(funcList != null && !funcList.isEmpty()){
                    funcRepository.deleteAll(funcList);
                }
            }
            menuRepository.deleteAll(menuList);
        }
        //删除权限相关信息
        List<SysAuthoGroup> authoGroupList = authoGroupRepository.findAllByProMark(project.getProMark());
        if(authoGroupList!=null && !authoGroupList.isEmpty()){
            for(SysAuthoGroup authoGroup:authoGroupList){
                List<SysAuthoGroupFunc> authoGroupFuncs = authoGroupFuncRepository.findAllByAgId(authoGroup.getId());
                if(authoGroupFuncs != null && !authoGroupFuncs.isEmpty()){
                    authoGroupFuncRepository.deleteAll(authoGroupFuncs);
                }
            }
            authoGroupRepository.deleteAll(authoGroupList);
        }
        List<SysAuthoRole> authoRoleList = authoRoleRepository.findAllByProMark(project.getProMark());
        if(authoRoleList!=null && !authoRoleList.isEmpty()){
            for(SysAuthoRole authoRole:authoRoleList){
                List<SysAuthoRoleFunc> authoRoleFuncs = authoRoleFuncRepository.findAllByArId(authoRole.getId());
                if(authoRoleFuncs != null && !authoRoleFuncs.isEmpty()){
                    authoRoleFuncRepository.deleteAll(authoRoleFuncs);
                }
            }
            authoRoleRepository.deleteAll(authoRoleList);
        }
        List<SysAuthoUser> authoUserList = authoUserRepository.findAllByProMark(project.getProMark());
        if(authoUserList!=null && !authoUserList.isEmpty()){
            for(SysAuthoUser authoUser:authoUserList){
                List<SysAuthoUserFunc> authoUserFuncs = authoUserFuncRepository.findAllByAuId(authoUser.getId());
                if(authoUserFuncs != null && !authoUserFuncs.isEmpty()){
                    authoUserFuncRepository.deleteAll(authoUserFuncs);
                }
            }
            authoUserRepository.deleteAll(authoUserList);
        }

        return ResultCommon.success();
    }

    /**
     * 更新项目信息
     * @param projectDTO
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysMenuProjectDTO> update(SysMenuProjectDTO projectDTO) throws Exception {
        Optional<SysMenuProject> projectOptional = projectRepository.findById(projectDTO.getId());
        if(!projectOptional.isPresent()){
            return ResultCommon.fail("项目信息不存在");
        }
        SysMenuProject project = projectMapper.toEntity(projectDTO);
        project = projectRepository.save(project);

        return ResultCommon.success().setData(projectMapper.toDTO(project));
    }

    @Override
    public ResultCommon<List<SysMenuProjectDTO>> searchAll() throws Exception {
        List<SysMenuProject> projectList = projectRepository.findAll();

        return ResultCommon.success().setData(projectMapper.toDTO(projectList));
    }

    /**
     * 分页查询功能列表
     * @param page
     * @param limit
     * @param menuId
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<PageData<SysBaseFuncDTO>> page(int page, int limit, Long menuId) throws Exception {
        Specification<SysBaseFunc> specification = new Specification<SysBaseFunc>() {
            @Override
            public Predicate toPredicate(Root<SysBaseFunc> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.equal(root.get("menuId"), menuId);
                return predicate;
            }
        };
        Pageable pageable = PageRequest.of(page-1, limit);

        Page<SysBaseFunc> funcPage = funcRepository.findAll(specification, pageable);

        return ResultCommon.success().setData(new PageData(page, limit, Long.valueOf(funcPage.getTotalElements()).intValue(),
                funcMapper.toDTO(funcPage.getContent())));
    }

    /**
     * 新增菜单功能信息
     * @param funcDTO
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseFuncDTO> save(SysBaseFuncDTO funcDTO) throws Exception {
        SysBaseFunc func = funcRepository.findFirstByFuncMarkAndMenuId(funcDTO.getFuncMark(), funcDTO.getMenuId());
        if(func != null){
            return ResultCommon.fail("菜单功能已存在");
        }
        func = funcMapper.toEntity(funcDTO);

        func = funcRepository.save(func);

        return ResultCommon.success().setData(funcMapper.toDTO(func));
    }

    /**
     * 更新菜单功能信息
     * @param funcDTO
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseFuncDTO> update(SysBaseFuncDTO funcDTO) throws Exception {
        Optional<SysBaseFunc> funcOptional = funcRepository.findById(funcDTO.getId());
        if(!funcOptional.isPresent()){
            return ResultCommon.fail("菜单功能不存在");
        }
        SysBaseFunc func = funcMapper.toEntity(funcDTO);
        func = funcRepository.save(func);
        return ResultCommon.success().setData(funcMapper.toDTO(func));
    }

    /**
     * 删除菜单功能信息
     * @param funcId
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<SysBaseFuncDTO> deleteFunc(Long funcId) throws Exception {
        Optional<SysBaseFunc> funcOptional = funcRepository.findById(funcId);
        if(!funcOptional.isPresent()){
            return ResultCommon.fail("菜单功能不存在");
        }
        SysBaseFunc func = funcOptional.get();

        funcRepository.delete(func);

        return ResultCommon.success();
    }

    /**
     * 获取项目全部菜单信息
     * @param proMark
     * @return
     * @throws Exception
     */
    @Override
    public ResultCommon<List<SysBaseMenuDTO>> searchMenus(String proMark) throws Exception {
        List<SysBaseMenu> menuList = menuRepository.findAllByProMark(proMark);
        List<SysBaseMenuDTO> menuDTOS = menuList.stream().map(sysBaseMenu -> {
            SysBaseMenuDTO menuDTO = menuMapperExpand.toDTO(sysBaseMenu);
            menuDTO = menuMapperExpand.getFuncs(menuDTO);
            return menuDTO;
        }).collect(Collectors.toList());
        return ResultCommon.success().setData(menuDTOS);
    }

    /**
     * 用户数据检校
     * @param obj
     * @param evaluateMethod
     * @return
     */
    private EvaluateInfo evaluate(Object obj, EvaluateMethod<Object> evaluateMethod){

        return evaluateMethod.evaluate(obj);
    }
}
